package org.linuxgears.bcf;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class Graph<Nw, Ew> implements Collection<Graph.Node<Nw>> {
	private Map<Node<Nw>, List<HalfEdge<Nw, Ew>>> im;

	public Graph() {
		im = new HashMap<Node<Nw>, List<HalfEdge<Nw,Ew>>>();
	}
	
	@Override
	public boolean add(Node<Nw> n) {
		if (! im.containsKey(n)) {
			im.put(n, null);
			return true;
		};
		return false;
	}

	@Override
	public boolean addAll(Collection<? extends Node<Nw>> c) {
		boolean modified = false;
		Iterator<? extends Node<Nw>>		 iter = c.iterator();
		for (;iter.hasNext();) {
			modified |= add(iter.next()); 
		}
		return modified;
	}

	@Override
	public void clear() {
		im = new HashMap<Node<Nw>, List<HalfEdge<Nw,Ew>>>();
	}

	@Override
	public boolean contains(Object o) {
		return im.containsKey(o);
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		Iterator<?> iter = c.iterator();
		boolean result = false;
		for (;iter.hasNext() && (result = contains(iter.next()));) {};
		return result;
	}

	@Override
	public boolean isEmpty() {
		return im.isEmpty();
	}

	@Override
	public Iterator<Node<Nw>> iterator() {
		return im.keySet().iterator();
	}

	@Override
	public boolean remove(Object o) {
		if (o instanceof Node<?>) {
			return (im.remove((Node<Nw>) o) != null);
		};
		return false;
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		boolean modified = false;
		Iterator<?> iter = c.iterator();
		for (;iter.hasNext();) {
			modified |= remove(iter.next());
		}
		return modified;
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		boolean modified = false;
		Iterator<?> iter = c.iterator();
		Object o;
		for (;iter.hasNext();) {
			o = iter.next();
			if (! contains(o)) {
				modified |= remove(o);
			}
		}
		return modified;		
	}

	@Override
	public int size() {
		return im.size();
	}

	@Override
	public Object[] toArray() {
		return im.keySet().toArray();
	}

	@Override
	public <T> T[] toArray(T[] a) {
		return null;
	}

	public static final class Node<nNw> {
		private nNw weight;
		
		public Node() {
			this.weight = null;
		}
		
		public Node(nNw w) {
			this.weight = w;
		}

		public nNw getWeight() {
			return weight;
		}
	}
	
	public static final class Edge<nNw, eEw> {
		private Node<nNw> source, target;
		private eEw weight;
		
		public Edge(Node<nNw> src, Node<nNw> tgt, eEw w) {
			this.source = src;
			this.target = tgt;
			this.weight = w;
		}
		
		public Node<nNw> getSource() {
			return source;
		}
		
		public Node<nNw> getTarget() {
			return target;
		}
		
		public eEw getWeight() {
			return weight;
		}
	}

	private static class HalfEdge<eNw, eEw> {
		private Node<eNw> targetNode;
		private eEw weight;

		public HalfEdge() {
			this.weight = null;
		}		
		
		public HalfEdge(eEw weight) {
			this.weight = weight;
		}
		
		public eEw getWeight() {
			return weight;
		}
		
		public Node<eNw> getNode() {
			return this.targetNode;
		}
		
		public Edge<eNw, eEw> toEdge(Node<eNw> node) {
			return new Edge<eNw, eEw>(node, targetNode, this.weight);
		}
	}
	
}